package android.contest.db;

import java.sql.Time;
import java.util.ArrayList;
import java.util.Calendar;

import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
import android.contest.R;
import android.contest.alarmclock.Alarms;
import android.contest.constant.Constant;
import android.contest.ui.TaskListView;
import android.contest.util.Log;
import android.contest.util.TimeUtil;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class AlarmDBMgr {
    private SQLiteOpenHelper mSQLiteHelper;
    
    private static final String DB_ENABLED_TABLE_NAME = "alarmEnabledTable";
    private static final String DB_SCHEDULED_TABLE_NAME = "alarmSheduledTable";
    
    public static final String COL_ALM_ID = "alm_id";
    private static final String COL_PERIOD = "period";
    private static final String COL_ENABLED = "enabled";
    private static final String COL_T1 = "t1";
    private static final String COL_T2 = "t2";
    private static final String COL_INCLUDE2 = "inclucde2";
    private static final String COL_T3 = "t3";
    private static final String COL_INCLUDE3 = "inclucde3";

    public static final String COL_TYPE_ID = "type_id";
    public static final String COL_ALERT_TIME = "alert_time";


    
    static private class DatabaseHelper extends SQLiteOpenHelper {
        private static final String DATABASE_NAME = "LaundryReminder.db";
        private static final int DATABASE_VERSION = 5;
        private Context context;

        public DatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        	this.context = context;
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
        	String execME = "CREATE TABLE IF NOT EXISTS "+DB_ENABLED_TABLE_NAME+" (" +
        			COL_ALM_ID + " INTEGER PRIMARY KEY, " +
        			COL_PERIOD + " INTEGER, " +
        			COL_ENABLED + " INTEGER, " +  // status: 0 off, 1 on. use integer as boolean
        			COL_T1 + " INTEGER, " +
        			COL_T2 + " INTEGER, " +
        			COL_INCLUDE2 + " INTEGER, " + 
        			COL_T3 + " INTEGER, " +
        			COL_INCLUDE3 + " INTEGER);";  
            db.execSQL( execME ); 
            if(Log.LOGV)Log.v(Log.LOGDB,execME);
            
            execME =  "CREATE TABLE IF NOT EXISTS "+DB_SCHEDULED_TABLE_NAME+" (" +
        			COL_ALM_ID + " INTEGER, " +
        			COL_TYPE_ID + " INTEGER, " +
        			COL_ALERT_TIME + " INTEGER);";
            db.execSQL( execME );
            if(Log.LOGV)Log.v(Log.LOGDB,execME);

            //insert default times
            long ta1 = (new Time(8,  0, 0)).getTime();
            long ta2 = (new Time(12, 0, 0)).getTime();
            long ta3 = (new Time(17, 0,0)).getTime();
            
            long tb1 = (new Time(8,  30, 0)).getTime();
            long tb2 = (new Time(12, 30, 0)).getTime();
            long tb3 = (new Time(17, 30,0)).getTime();

            // insert the first default task
            String insertE = "INSERT INTO "+DB_ENABLED_TABLE_NAME+" ( " +COL_PERIOD+ ", " +COL_ENABLED+", "+COL_T1+", "+COL_T2+", "+COL_INCLUDE2+", "+COL_T3+","+COL_INCLUDE3+") ";
            insertE +=	" VALUES (1,0,"+ 
            		(new Long(ta1)).toString() + ", " +
            		(new Long(ta2)).toString() + ", " +
            		0 + ", " +      //include2 = false
            		(new Long(ta3)).toString() + ", " +
            		0 + ");";       //include3 = false
            if(Log.LOGV)Log.v(Log.LOGDB,insertE);

            db.execSQL(insertE);
            Cursor cur = db.rawQuery("select last_insert_rowid();", null);
            cur.moveToFirst();
//            int colnum = cur.getColumnCount();
//            if(Log.LOGV)Log.v(Log.LOGDB,"Column number is: "+ new Integer(colnum).toString());
//            String [] names  = cur.getColumnNames();
//            for(int i = 0; i<colnum; i++){
//                if(Log.LOGV)Log.v(Log.LOGDB,i+ ": "+names[i]);
//            }
            Integer[] alm_id = new Integer[2];
            int col = cur.getColumnIndexOrThrow("last_insert_rowid()");
            alm_id[0] = cur.getInt(col);
            cur.close();
            
            // insert the second default task
            insertE = "INSERT INTO "+DB_ENABLED_TABLE_NAME+" ( " +COL_PERIOD+ ", " +COL_ENABLED+", "+COL_T1+", "+COL_T2+", "+COL_INCLUDE2+", "+COL_T3+","+COL_INCLUDE3+") ";
            insertE +=	" VALUES (1,0,"+ 
            		(new Long(tb1)).toString() + ", " +
            		(new Long(tb2)).toString() + ", " +
            		0 + ", " +       //include2 = false
            		(new Long(tb3)).toString()+ ", " +
            		0 + ");";        //include3 = false
            if(Log.LOGV)Log.v(Log.LOGDB,insertE);
            db.execSQL(insertE);
            cur = db.rawQuery("select last_insert_rowid();", null);
            cur.moveToFirst();
            alm_id[1] = cur.getInt(col);
            cur.close();
            
            //insert default value for preferences file by Wang Jingjing at 9:13            
            String defaultPreferencesFileName = TaskListView.PREFIX_PREFERENCES_FILE_NAME + alm_id[0].toString();
			System.out.println("defaultPreferencesFileName in DBMgr = " + defaultPreferencesFileName );
            SharedPreferences defaultPreferences = context.getSharedPreferences(defaultPreferencesFileName, Activity.MODE_PRIVATE);
            SharedPreferences.Editor defaultEditor = defaultPreferences.edit();
            defaultEditor.putString(context.getResources().getString(R.string.service_name), context.getResources().getString(R.string.shirts));
            defaultEditor.putBoolean(context.getResources().getString(R.string.status), false);
            defaultEditor.putString(context.getResources().getString(R.string.ringtone), "");
            defaultEditor.putString(context.getResources().getString(R.string.service_condition), (context.getResources().getStringArray(R.array.conditionValues)[0]));
            /*new time info*/
            defaultEditor.putBoolean(context.getResources().getString(R.string.step2_included), false);
            defaultEditor.putBoolean(context.getResources().getString(R.string.step3_included), false);
            defaultEditor.putString(context.getResources().getString(R.string.step1_description), 
            		context.getResources().getString(R.string.step1_description_value) + " " + context.getResources().getString(R.string.shirts));
            defaultEditor.putString(context.getResources().getString(R.string.step2_description), 
            		context.getResources().getString(R.string.step2_description_value) + " " + context.getResources().getString(R.string.shirts));
            defaultEditor.putString(context.getResources().getString(R.string.step3_description), 
            		context.getResources().getString(R.string.step3_description_value));
            defaultEditor.putString(context.getResources().getString(R.string.step1_time), "8:00 AM");
            defaultEditor.putString(context.getResources().getString(R.string.step2_time), "12:00");
            defaultEditor.putString(context.getResources().getString(R.string.step3_time), "17:00");
            /*new time info*/
            defaultEditor.commit();
            
            defaultPreferencesFileName = TaskListView.PREFIX_PREFERENCES_FILE_NAME + alm_id[1].toString();
            defaultPreferences = context.getSharedPreferences(defaultPreferencesFileName, Activity.MODE_PRIVATE);
            defaultEditor = defaultPreferences.edit();
            defaultEditor.putString(context.getResources().getString(R.string.service_name), context.getResources().getString(R.string.quilts));
            defaultEditor.putBoolean(context.getResources().getString(R.string.status), false);
            defaultEditor.putString(context.getResources().getString(R.string.ringtone), "");
            defaultEditor.putString(context.getResources().getString(R.string.service_condition), (context.getResources().getStringArray(R.array.conditionValues)[0]));
            /*new time info*/
            defaultEditor.putBoolean(context.getResources().getString(R.string.step2_included), false);
            defaultEditor.putBoolean(context.getResources().getString(R.string.step3_included), false);
            defaultEditor.putString(context.getResources().getString(R.string.step1_description), 
            		context.getResources().getString(R.string.step1_description_value) + " " + context.getResources().getString(R.string.quilts));
            defaultEditor.putString(context.getResources().getString(R.string.step2_description), 
            		context.getResources().getString(R.string.step2_description_value) + " " + context.getResources().getString(R.string.quilts));
            defaultEditor.putString(context.getResources().getString(R.string.step3_description), 
            		context.getResources().getString(R.string.step3_description_value));
            defaultEditor.putString(context.getResources().getString(R.string.step1_time), "8:30 AM");
            defaultEditor.putString(context.getResources().getString(R.string.step2_time), "12:30");
            defaultEditor.putString(context.getResources().getString(R.string.step3_time), "17:30");
            defaultEditor.commit();
        }

        
		@Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {
            if (Log.LOGV) Log.v(
                    "Upgrading alarms database from version " +
                    oldVersion + " to " + currentVersion +
                    ", which will destroy all old data");
            db.execSQL("DROP TABLE IF EXISTS alarms");
            onCreate(db);
        }
    }
	
	public AlarmDBMgr(Context context){
		this.mSQLiteHelper = new DatabaseHelper(context);
//		if(Log.LOGV) Log.v(Log.LOGDB, "AlarmDBMgr.AlarmDBMgr(): mSQLiteHelper =" +mSQLiteHelper );
//		if(Log.LOGV) Log.v(Log.LOGDB, "AlarmDBMgr.AlarmDBMgr(): LaundryReminderApp.getInstance() =" +LaundryReminderApp.getInstance() );
	}
	
	public ArrayList<Long> getIDs(){
//		if(Log.LOGV) Log.v(Log.LOGDB, "AlarmDBMgr.getID(): mSQLiteHelper = " +mSQLiteHelper );
		SQLiteDatabase db = mSQLiteHelper.getReadableDatabase();
		ArrayList<Long> idList = new ArrayList<Long>();
		Cursor cur = db.query(DB_ENABLED_TABLE_NAME, new String[]{COL_ALM_ID}, null, null, null, null, null/*COL_ALM_ID+" desc"*/);
		int col = cur.getColumnIndexOrThrow(COL_ALM_ID);
		while(cur.moveToNext()){
			idList.add(cur.getLong(col));
		}
		cur.close();
		db.close();
		return idList;
	}
	public long createDBItem(){
		return this.insertItem(0, 0, 0, 1/*3*//*Modified by WJJ*/, false);
	}
	
	public boolean updateDBItem(int id, long T1, long T2, long T3){
		// the default alarm period is 3 days
		return this.updateDBItem(id, T1, T2, T3, 3);
	}
	
	public boolean updateDBItem(long id, long T1, long T2, long T3, int period){
		// the sub items are default not included
		return this.updateDBItem(id, T1, T2, false, T3, false, period);
	}
	
	public boolean updateDBItem(long id, long T1, long T2, boolean include2, long T3, boolean include3, int period){
		return this.updateItem2(id, T1, T2, include2, T3, include3, period);
	}


	public boolean deletedDBItem(long id){
		return this.deleteItem(id);
	}
	
	public boolean enableDBItem(long id){
		return this.setItemEnabled(id, true);
	}
	
	public boolean disableDBItem(long id){
		return this.setItemEnabled(id, false);
	}
	
	
	/**
     * private method to insert a new alarm, the only way to insert item to alarm database
     */

	private long insertItem(long t1, long t2, long t3, int period, boolean b) {
		SQLiteDatabase db = mSQLiteHelper.getWritableDatabase();
		
//		String insertE = "INSERT INTO alarmEnabledTable (period, enabled) VALUES ("+(new Integer(period)).toString()+","+(b?"1":"0")+")";
//        String insertE = "INSERT INTO "+DB_ENABLED_TABLE_NAME+" ( " +COL_PERIOD+ ", " +COL_ENABLED+", "+COL_T1+", "+COL_T2+", "+COL_T3+") ";
//        insertE +=	" VALUES ("+(new Integer(period)).toString()+","+(b?"1":"0")+","+ 
//        		(new Long(t1)).toString() + ", " +
//        		(new Long(t2)).toString() + ", " +
//        		(new Long(t3)).toString()+");";
//        
//        db.execSQL(insertE);
        ContentValues cv = new ContentValues();
        cv.put(COL_PERIOD, period);
        cv.put(COL_ENABLED, b?1:0);
        cv.put(COL_T1, t1);
        cv.put(COL_T2, t2);
        cv.put(COL_T3, t3);
        long rowid = db.insertOrThrow(DB_ENABLED_TABLE_NAME, null, cv);
        if(Log.LOGV)Log.v(Log.LOGDB, "AlarmDBMgr.insertItem(): the new rowid returned = " + rowid);
        Cursor cur = db.rawQuery("select last_insert_rowid();", null);
        cur.moveToFirst();
        int col = cur.getColumnIndexOrThrow("last_insert_rowid()");
        Integer alm_id = cur.getInt(col);
        if(Log.LOGV)Log.v(Log.LOGDB, "AlarmDBMgr.insertItem(): the new rowid queried= " + alm_id);
        if(Constant.DEBUG)
        	if(alm_id!=rowid)
        		throw new java.lang.Error();
        cur.close();
		db.close();
        return rowid;
	}
	
	
	private boolean updateItem(long id, long t1, long t2, boolean include2,
			long t3, boolean include3, int period) {
		if(Log.LOGV)Log.v(Log.LOGDB, "AlarmDBMgr.updateItem(): id="+id+", t1="+t1+", t2="+t2+"t2_included="+include2+", t3="+t3+"t3_included="+include3+", period="+period);
		dump();
		SQLiteDatabase db = mSQLiteHelper.getWritableDatabase();
		ContentValues cve = new ContentValues();
		cve.put(COL_PERIOD, period);
		cve.put(COL_T1, t1);
		cve.put(COL_T2, t2);
		cve.put(COL_INCLUDE2, include2?1:0);
		cve.put(COL_T3, t3);
		cve.put(COL_INCLUDE3, include3?1:0);
		int count = db.update(DB_ENABLED_TABLE_NAME, cve, COL_ALM_ID + "=" + id, null);
		if(Log.LOGV)Log.v(Log.LOGDB, "AlarmDBMgr.updateItem(): after update EnabledTable");
		Cursor cur = db.query(DB_ENABLED_TABLE_NAME, new String[]{COL_ENABLED, COL_T1, COL_T2, COL_INCLUDE2, COL_T3, COL_INCLUDE3}, COL_ALM_ID + "=" + id, null, null, null, null/*COL_ALM_ID+" desc"*/);
		int col_enabled = cur.getColumnIndexOrThrow(COL_ENABLED);
		int col_t1 = cur.getColumnIndexOrThrow(COL_T1);
		int col_t2 = cur.getColumnIndexOrThrow(COL_T2);
//		int col_include2 = cur.getColumnIndexOrThrow(COL_INCLUDE2);
		int col_t3 = cur.getColumnIndexOrThrow(COL_T3);
//		int col_include3 = cur.getColumnIndexOrThrow(COL_INCLUDE3);
		cur.moveToFirst();
		
		boolean enabled = cur.getInt(col_enabled) == 1;
		if(enabled){
			long milli_t1 = cur.getLong(col_t1);
			long milli_t2 = cur.getLong(col_t2);
			long milli_t3 = cur.getLong(col_t3);
			
			if(Log.LOGV){
				TimeUtil.reportTimeInDay("AlarmDBMgr.updateItem():t1", milli_t1);
				TimeUtil.reportTimeInDay("AlarmDBMgr.updateItem():t2", milli_t2);
				Log.v(Log.LOGDB, "AlarmDBMgr.updateItem():t2 is "+(include2?"included":"Not included"));
				TimeUtil.reportTimeInDay("AlarmDBMgr.updateItem():t3", milli_t3);
				Log.v(Log.LOGDB, "AlarmDBMgr.updateItem():t3 is "+(include3?"included":"Not included"));			
			}
			
//			// check the alarms already scheduled in the alarmScheduledTable
//			Cursor cur_sched = db.query(DB_SCHEDULED_TABLE_NAME, new String[]{COL_ALM_ID, COL_TYPE_ID, COL_ALERT_TIME}, COL_ALM_ID + " = " + id, null, null, null, COL_ALERT_TIME);
//			if(cur_sched.getCount() <0 || cur_sched.getCount()>5)
//				throw new java.lang.Error("cur_sched.getCount() is "+cur_sched.getCount());
//			cur_sched.moveToFirst();
//			long nearest_alm_time = cur_sched.getLong(cur_sched.getColumnIndexOrThrow(COL_ALERT_TIME)); //the nearest time
//			int nearest_type_id = cur_sched.getInt(cur_sched.getColumnIndexOrThrow(COL_TYPE_ID));
//			
//			long wash_time = 0;
//			// find out the first alarm's date
//			switch(nearest_type_id){
//			case Constant.WASH_CLOTHES:
//				scheduleNextEpoch(id, nearest_alm_time);
//				break;
//			case Constant.DRY_CLOTHES:
//				if(!cur_sched.move(2))
//					throw new java.lang.Error("move to wash time failure!");
//				wash_time = cur_sched.getLong(cur_sched.getColumnIndexOrThrow(COL_ALERT_TIME));
//				break;
//			case Constant.COLLECT_CLOTHES:
//				if(cur_sched.move(1))
//					throw new java.lang.Error("move to wash time failure!");
//				wash_time = cur_sched.getLong(cur_sched.getColumnIndexOrThrow(COL_ALERT_TIME));
//				break;
//				default:
//					throw new java.lang.Error("unkown type_id!");
//			}
			
	        Calendar c = Calendar.getInstance();
	        c.setTimeInMillis(System.currentTimeMillis());
//	        c.setTimeInMillis(wash_time);
	        
	        
	        long now = new Time(c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE), c.get(Calendar.SECOND)).getTime();
	        int day_adv = milli_t1 < now? 1: 0; // if time1 has passed today, schedule for the next day
	        TimeUtil.reportTimeInDay("AlarmDBMgr.updateItem():now=", now);
	        TimeUtil.reportTimeInDay("AlarmDBMgr.updateItem():milli_t1=", milli_t1);
	        Log.v(Log.LOGDB, "AlarmDBMgr.updateItem():day_adv="+day_adv);

	        
			Calendar c_t1 = Alarms.calculateAlarm2(milli_t1, day_adv);
			Calendar c_t2 = Alarms.calculateAlarm2(milli_t1+milli_t2, day_adv);
			Calendar c_t3 = Alarms.calculateAlarm2(milli_t1+milli_t2+milli_t3, day_adv);
			if(Log.LOGV){
				TimeUtil.reportCalendarTime("AlarmDBMgr.updateItem():ct1", c_t1);
				TimeUtil.reportCalendarTime("AlarmDBMgr.updateItem():ct2", c_t2);
				TimeUtil.reportCalendarTime("AlarmDBMgr.updateItem():ct3", c_t3);
			}
			long datetime_t1 = c_t1.getTimeInMillis();
			long datetime_t2 = c_t2.getTimeInMillis();
			long datetime_t3 = c_t3.getTimeInMillis();
//			if(Log.LOGV){
//				Log.v(Log.LOGDB, "AlarmDBMgr.scheduleNextEpoch():");
//				TimeUtil.reportTimeMillis("dt1", datetime_t1);
//				TimeUtil.reportTimeMillis("dt2", datetime_t2);
//				TimeUtil.reportTimeMillis("dt3", datetime_t3);
//			}
			
			ContentValues cv1 = new ContentValues();
			cv1.put(COL_ALERT_TIME, datetime_t1);
			int count1 = db.update(DB_SCHEDULED_TABLE_NAME, cv1, COL_ALM_ID + " = " + id + " AND " + COL_TYPE_ID + " = " + Constant.WASH_CLOTHES, null);
			Log.v(Log.LOGDB, "AlarmDBMgr.updateItem():" + COL_ALM_ID + " = " + id + " AND " + COL_TYPE_ID + " = " + Constant.WASH_CLOTHES);

			int count2 = db.delete(DB_SCHEDULED_TABLE_NAME, COL_ALM_ID + " = " + id + " AND " + COL_TYPE_ID + " = " + Constant.DRY_CLOTHES, null);
			int count3 = db.delete(DB_SCHEDULED_TABLE_NAME, COL_ALM_ID + " = " + id + " AND " + COL_TYPE_ID + " = " + Constant.COLLECT_CLOTHES, null);
			if(include2){
				ContentValues cv2 = new ContentValues();
				cv2.put(COL_ALM_ID, id);
				cv2.put(COL_TYPE_ID, Constant.DRY_CLOTHES);
				cv2.put(COL_ALERT_TIME, datetime_t2);
				db.insertOrThrow(DB_SCHEDULED_TABLE_NAME, null, cv2);
				
				if(include3){
					ContentValues cv3 = new ContentValues();
					cv3.put(COL_ALM_ID, id);
					cv3.put(COL_TYPE_ID, Constant.COLLECT_CLOTHES);
					cv3.put(COL_ALERT_TIME, datetime_t3);
					db.insertOrThrow(DB_SCHEDULED_TABLE_NAME, null, cv3);
				}
			}
			
			
			
//			/*It does not matter as setNextAlert will delete the obsolete alarm*/			
//			if(count1 != 1 /*|| count2 != 1 || count3 != 1*/)
//				throw new java.lang.Error("This should not happen, count1=" + count1 + ", count2=" + count2 + ", count3="+ count3);
			
			cur.close();						
		}
		
		db.close();
		boolean successflag = count == 1;
		if(Log.LOGV){
			if(successflag)
				Log.v(Log.LOGDB, "AlarmDBMgr.updateItem() operation successfully");
			else
				Log.v(Log.LOGDB, "AlarmDBMgr.updateItem() operation failure!!");
		}
		return successflag; // of 1 column is update return a successful update
	}
	
	/***
	 * updateItem2 Modified from updateItem By WJJ
	 * Update "the enable table" according to just what the params say;
	 * Update "the schedule table": the alarm pool contains the possible alarms for all tasks 
	 * where "possible" means the alarm time is always in the future.  
	 * @param id
	 * @param t1
	 * @param t2
	 * @param include2
	 * @param t3
	 * @param include3
	 * @param period
	 * @return
	 */
	private boolean updateItem2(long id, long t1, long t2, boolean include2,
			long t3, boolean include3, int period) {
		//update "the enable table"
		if(Log.LOGV)Log.v(Log.LOGDB, "AlarmDBMgr.updateItem(): id="+id+", t1="+t1+", t2="+t2+"t2_included="+include2+", t3="+t3+"t3_included="+include3+", period="+period);
		dump();
		SQLiteDatabase db = mSQLiteHelper.getWritableDatabase();
		ContentValues cve = new ContentValues();
		cve.put(COL_PERIOD, period);
		cve.put(COL_T1, t1);
		cve.put(COL_T2, t2);
		cve.put(COL_INCLUDE2, include2?1:0);
		cve.put(COL_T3, t3);
		cve.put(COL_INCLUDE3, include3?1:0);
		int count = db.update(DB_ENABLED_TABLE_NAME, cve, COL_ALM_ID + "=" + id, null);
		if(Log.LOGV)Log.v(Log.LOGDB, "AlarmDBMgr.updateItem(): after update EnabledTable");
		Cursor cur = db.query(DB_ENABLED_TABLE_NAME, new String[]{COL_ENABLED, COL_T1, COL_T2, COL_INCLUDE2, COL_T3, COL_INCLUDE3, COL_PERIOD}, COL_ALM_ID + "=" + id, null, null, null, null/*COL_ALM_ID+" desc"*/);
		int col_enabled = cur.getColumnIndexOrThrow(COL_ENABLED);
		int col_t1 = cur.getColumnIndexOrThrow(COL_T1);
		int col_t2 = cur.getColumnIndexOrThrow(COL_T2);
//		int col_include2 = cur.getColumnIndexOrThrow(COL_INCLUDE2);
		int col_t3 = cur.getColumnIndexOrThrow(COL_T3);
//		int col_include3 = cur.getColumnIndexOrThrow(COL_INCLUDE3);
		int col_period = cur.getColumnIndexOrThrow(COL_PERIOD);
		cur.moveToFirst();
		
		//If task enabled, the 1/2/3 possible alarm(s) will be put into the alarm pool
		boolean enabled = cur.getInt(col_enabled) == 1;
		if(enabled){
			long milli_t1 = cur.getLong(col_t1);
			long milli_t2 = cur.getLong(col_t2);
			long milli_t3 = cur.getLong(col_t3);
			int item_period = cur.getInt(col_period);
			
			if(Log.LOGV){
				TimeUtil.reportTimeInDay("AlarmDBMgr.updateItem():t1", milli_t1);
				TimeUtil.reportTimeInDay("AlarmDBMgr.updateItem():t2", milli_t2);
				Log.v(Log.LOGDB, "AlarmDBMgr.updateItem():t2 is "+(include2?"included":"Not included"));
				TimeUtil.reportTimeInDay("AlarmDBMgr.updateItem():t3", milli_t3);
				Log.v(Log.LOGDB, "AlarmDBMgr.updateItem():t3 is "+(include3?"included":"Not included"));			
			}
						
	        Calendar c = Calendar.getInstance();
	        c.setTimeInMillis(System.currentTimeMillis());	        
	        
	        long now = new Time(c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE), c.get(Calendar.SECOND)).getTime();
	        int day_adv;
	        
	        //what if the period is not 1? but 7?!
	        day_adv = milli_t1 < now? item_period: 0; // if time1 has passed today, schedule for the next day
	        Calendar c_t1 = Alarms.calculateAlarm2(milli_t1, day_adv);
			
	        day_adv = milli_t1+milli_t2 < now? item_period: 0;
	        Calendar c_t2 = Alarms.calculateAlarm2(milli_t1+milli_t2, day_adv);
	        
	        day_adv = milli_t1+milli_t2+milli_t3 < now? item_period:0;
			Calendar c_t3 = Alarms.calculateAlarm2(milli_t1+milli_t2+milli_t3, day_adv);
			if(Log.LOGV){
				TimeUtil.reportCalendarTime("AlarmDBMgr.updateItem():ct1", c_t1);
				TimeUtil.reportCalendarTime("AlarmDBMgr.updateItem():ct2", c_t2);
				TimeUtil.reportCalendarTime("AlarmDBMgr.updateItem():ct3", c_t3);
			}
			long datetime_t1 = c_t1.getTimeInMillis();
			long datetime_t2 = c_t2.getTimeInMillis();
			long datetime_t3 = c_t3.getTimeInMillis();
			
			ContentValues cv1 = new ContentValues();
			cv1.put(COL_ALERT_TIME, datetime_t1);
			int count1 = db.update(DB_SCHEDULED_TABLE_NAME, cv1, COL_ALM_ID + " = " + id + " AND " + COL_TYPE_ID + " = " + Constant.WASH_CLOTHES, null);
			Log.v(Log.LOGDB, "AlarmDBMgr.updateItem():" + COL_ALM_ID + " = " + id + " AND " + COL_TYPE_ID + " = " + Constant.WASH_CLOTHES);

			int count2 = db.delete(DB_SCHEDULED_TABLE_NAME, COL_ALM_ID + " = " + id + " AND " + COL_TYPE_ID + " = " + Constant.DRY_CLOTHES, null);
			int count3 = db.delete(DB_SCHEDULED_TABLE_NAME, COL_ALM_ID + " = " + id + " AND " + COL_TYPE_ID + " = " + Constant.COLLECT_CLOTHES, null);
			if(include2){
				ContentValues cv2 = new ContentValues();
				cv2.put(COL_ALM_ID, id);
				cv2.put(COL_TYPE_ID, Constant.DRY_CLOTHES);
				cv2.put(COL_ALERT_TIME, datetime_t2);
				db.insertOrThrow(DB_SCHEDULED_TABLE_NAME, null, cv2);
				
				if(include3){
					ContentValues cv3 = new ContentValues();
					cv3.put(COL_ALM_ID, id);
					cv3.put(COL_TYPE_ID, Constant.COLLECT_CLOTHES);
					cv3.put(COL_ALERT_TIME, datetime_t3);
					db.insertOrThrow(DB_SCHEDULED_TABLE_NAME, null, cv3);
				}
			}
			
			
			
			/*It matters! if there are more than one alarm we must have a bug!*/			
			if(count1 != 1 /*|| count2 != 1 || count3 != 1*/)
				throw new java.lang.Error("This should not happen, count1=" + count1 + ", count2=" + count2 + ", count3="+ count3);
			
			cur.close();						
		}
		
		db.close();
		boolean successflag = count == 1;
		if(Log.LOGV){
			if(successflag)
				Log.v(Log.LOGDB, "AlarmDBMgr.updateItem() operation successfully");
			else
				Log.v(Log.LOGDB, "AlarmDBMgr.updateItem() operation failure!!");
		}
		return successflag; // of 1 column is update return a successful update
	}
	
//	old verion update, which does not support sub-item on and off 
//	private boolean updateItem(long id, long t1, long t2, long t3, int period) {
////		if(Log.LOGV)Log.v(Log.LOGDB, "AlarmDBMgr.updateItem(): id="+id+", t1="+t1+", t2="+t2+", t3="+t3+", period="+period);
//		SQLiteDatabase db = mSQLiteHelper.getWritableDatabase();
//		ContentValues cve = new ContentValues();
//		cve.put(COL_PERIOD, period);
//		cve.put(COL_T1, t1);
//		cve.put(COL_T2, t2);
//		cve.put(COL_T3, t3);
////		if(db.isOpen())
////			Log.v(Log.LOGDB,"AlarmDBMgr.updateItem(): db is opened");
////		else
////			Log.v(Log.LOGDB,"AlarmDBMgr.updateItem(): db is not open!!!");
////		if(Log.LOGV){
////			Log.v(Log.LOGDB,"AlarmDBMgr.updateItem(): dump before update-------------");
////			this.dumpEnabledTable();
////		}
//		int count = db.update(DB_ENABLED_TABLE_NAME, cve, COL_ALM_ID + "=" + id, null);
////		if(Log.LOGV){
////			Log.v(Log.LOGDB,"AlarmDBMgr.updateItem(): dump after update-------------");
////			this.dumpEnabledTable();
////		}
//
//		Cursor cur = db.query(DB_ENABLED_TABLE_NAME, new String[]{COL_ENABLED, COL_T1, COL_T2, COL_T3}, COL_ALM_ID + "=" + id, null, null, null, null/*COL_ALM_ID+" desc"*/);
//		int col_enabled = cur.getColumnIndexOrThrow(COL_ENABLED);
//		int col_t1 = cur.getColumnIndexOrThrow(COL_T1);
//		int col_t2 = cur.getColumnIndexOrThrow(COL_T2);
//		int col_t3 = cur.getColumnIndexOrThrow(COL_T3);
//		cur.moveToFirst();
//		
//		boolean enabled = cur.getInt(col_enabled) == 1;
//		if(enabled){
//			long milli_t1 = cur.getLong(col_t1);
//			long milli_t2 = cur.getLong(col_t2);
//			long milli_t3 = cur.getLong(col_t3);
//			
//			Time time_t1 = new Time(milli_t1);
//			Time time_t2 = new Time(milli_t2);
//			Time time_t3 = new Time(milli_t3);
//			if(Log.LOGV)Log.v(Log.LOGDB, 
//					"AlarmDBMgr.updateItem(): Time is t1 = " +time_t1.toString() + ", " +
//							"t2 = " +time_t2.toString() + ", " +
//							"t3 = " +time_t3.toString());
//			
//	        Calendar c = Calendar.getInstance();
//	        c.setTimeInMillis(System.currentTimeMillis());
//	        long now = new Time(c.get(c.HOUR_OF_DAY), c.get(Calendar.MINUTE), c.get(Calendar.SECOND)).getTime();
//	        int day_adv = milli_t1 < now? 0: 1; // if time1 has passed today, schedule for the next day
//
////	        Calendar c_t1 = Alarms.calculateAlarm(0, time_t1.getHours(), time_t1.getMinutes());
////			Calendar c_t2 = Alarms.calculateAlarm(1, time_t2.getHours(), time_t2.getMinutes());
////			Calendar c_t3 = Alarms.calculateAlarm(1, time_t3.getHours(), time_t3.getMinutes());
//
//			Calendar c_t1 = Alarms.calculateAlarm2(milli_t1, day_adv);
//			Calendar c_t2 = Alarms.calculateAlarm2(milli_t1+milli_t2, day_adv);
//			Calendar c_t3 = Alarms.calculateAlarm2(milli_t1+milli_t2+milli_t3, day_adv);
//			if(Log.LOGV)Log.v(Log.LOGDB, 
//					"AlarmDBMgr.updateItem(): Calendar is ct1 = " +c_t1.getTime().toString() + ", " +
//								"ct2 = " +c_t2.getTime().toString() + ", " +
//								"ct3 = " +c_t3.getTime().toString());
//			long datetime_t1 = c_t1.getTimeInMillis();
//			long datetime_t2 = c_t2.getTimeInMillis();
//			long datetime_t3 = c_t3.getTimeInMillis();
//			if(Log.LOGV)Log.v(Log.LOGDB, 
//					"AlarmDBMgr.updateItem(): Datetime is dt1 = " +datetime_t1 + ", " +
//								"dt2 = " +datetime_t2 + ", " +
//								"dt3 = " +datetime_t3);
//			ContentValues cv1 = new ContentValues();
//			cv1.put(COL_ALERT_TIME, datetime_t1);
//			int count1 = db.update(DB_SCHEDULED_TABLE_NAME, cv1, COL_ALM_ID + " = " + id + " AND " + COL_TYPE_ID + " = " + Constant.WASH_CLOTHES, null);
//			
//			ContentValues cv2 = new ContentValues();
//			cv2.put(COL_ALERT_TIME, datetime_t2);
//			int count2 = db.update(DB_SCHEDULED_TABLE_NAME, cv2, COL_ALM_ID + " = " + id + " AND " + COL_TYPE_ID + " = " + Constant.DRY_CLOTHES, null);
//			
//			ContentValues cv3 = new ContentValues();
//			cv3.put(COL_ALERT_TIME, datetime_t3);
//			int count3 = db.update(DB_SCHEDULED_TABLE_NAME, cv3, COL_ALM_ID + " = " + id + " AND " + COL_TYPE_ID + " = " + Constant.COLLECT_CLOTHES, null);
//			
//			if(count1 != 1 || count2 != 1 || count3 != 1)
//				throw new java.lang.Error("This should not happen.");
//			
//			cur.close();
//		}
//		
//		db.close();
//		boolean successflag = count == 1;
//		if(Log.LOGV){
//			if(successflag)
//				Log.v(Log.LOGDB, "AlarmDBMgr.updateItem() operation successfully");
//			else
//				Log.v(Log.LOGDB, "AlarmDBMgr.updateItem() operation failure!!");
//		}
//		return successflag; // of 1 column is update return a successful update
//	}

	private boolean setItemEnabled(long id, boolean b){
		Log.v(Log.LOGDB, "AlarmDBMgr.setItemEnabled(): id="+id +", b="+ b);
		SQLiteDatabase db = mSQLiteHelper.getWritableDatabase();
		
		Cursor checkBValue_cur = db.query(DB_ENABLED_TABLE_NAME, new String[]{AlarmDBMgr.COL_ENABLED, AlarmDBMgr.COL_PERIOD}, AlarmDBMgr.COL_ALM_ID + "=" +id,
				null, null, null, null);
		int col_enabled = checkBValue_cur.getColumnIndexOrThrow(AlarmDBMgr.COL_ENABLED);
		int col_period = checkBValue_cur.getColumnIndexOrThrow(AlarmDBMgr.COL_PERIOD);
		if(checkBValue_cur.moveToFirst()){
			if( (checkBValue_cur.getInt(col_enabled) == 1) && b)
				return true;
			if( (checkBValue_cur.getInt(col_enabled) == 0) && !b)
				return true;
		}
		else Log.v("AlarmDBMgr.setItemEnabled(): no item with this id" + id);
		int period = checkBValue_cur.getInt(col_period);
		checkBValue_cur.close();
		
		ContentValues cve = new ContentValues();
		cve.put(COL_ENABLED, b?1:0);
		int count = db.update(DB_ENABLED_TABLE_NAME, cve, COL_ALM_ID + "=" + id, null);

		boolean successflag;
		if(b){ // enable the task. schedule the latest 3 event (wash, dry, collect) in to the alarmScheduleTime
			long datetime_t1, datetime_t2, datetime_t3;
			Cursor cur = db.query(DB_ENABLED_TABLE_NAME, new String[]{COL_T1, COL_T2, COL_INCLUDE2, COL_T3, COL_INCLUDE3}, COL_ALM_ID + "=" + id, null, null, null, null/*COL_ALM_ID+" desc"*/);
			int col_t1 = cur.getColumnIndexOrThrow(COL_T1);
			int col_t2 = cur.getColumnIndexOrThrow(COL_T2);
			int col_include2 = cur.getColumnIndexOrThrow(COL_INCLUDE2);
			int col_t3 = cur.getColumnIndexOrThrow(COL_T3);
			int col_include3 = cur.getColumnIndexOrThrow(COL_INCLUDE3);
			
			if(cur.getCount()!=1)
				throw new java.lang.Error("cur.getCount() = " + cur.getCount());
			cur.moveToFirst();

			long milli_t1 = cur.getLong(col_t1);
			long milli_t2 = cur.getLong(col_t2);
			boolean include2 = cur.getInt(col_include2) == 1;
			long milli_t3 = cur.getLong(col_t3);
			boolean include3 = cur.getInt(col_include3) == 1;

			
			if(Log.LOGV){
				TimeUtil.reportTimeInDay("AlarmDBMgr.setItemEnabled():t1", milli_t1);
				TimeUtil.reportTimeInDay("AlarmDBMgr.setItemEnabled():t2", milli_t2);
				Log.v(Log.LOGDB, "AlarmDBMgr.setItemEnabled():t2 is "+(include2?"included":"Not included"));
				TimeUtil.reportTimeInDay("t3", milli_t3);
				Log.v(Log.LOGDB, "AlarmDBMgr.setItemEnabled():t3 is "+(include3?"included":"Not included"));			}
			
			Calendar c = Calendar.getInstance();
	        c.setTimeInMillis(System.currentTimeMillis());
	        long now = new Time(c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE), c.get(Calendar.SECOND)).getTime();
//	        Log.v(Log.LOGDB, "AlarmDBMgr.setItemEnabled(): Time now="+time_now.toString()+", time t1="+time_t1.toString()+", t1<now: "+(milli_t1< now?"true":"false"));
	        int day_adv = now < milli_t1 ? 0: period;//1; // if time1 has passed today, schedule for the next day

			Calendar c_t1 = Alarms.calculateAlarm2(milli_t1, day_adv);
			Calendar c_t2 = Alarms.calculateAlarm2(milli_t1+milli_t2, day_adv);
			Calendar c_t3 = Alarms.calculateAlarm2(milli_t1+milli_t2+milli_t3, day_adv);
			
			datetime_t1 = c_t1.getTimeInMillis();
			datetime_t2 = c_t2.getTimeInMillis();
			datetime_t3 = c_t3.getTimeInMillis();
			
			ContentValues cv1 = new ContentValues();
			cv1.put(COL_ALM_ID, id);
			cv1.put(COL_TYPE_ID, Constant.WASH_CLOTHES);
			cv1.put(COL_ALERT_TIME, datetime_t1);
			long rv1 = db.insert(DB_SCHEDULED_TABLE_NAME, null, cv1);
			
			if(include2){
				ContentValues cv2 = new ContentValues();
				cv2.put(COL_ALM_ID, id);
				cv2.put(COL_TYPE_ID, Constant.DRY_CLOTHES);
				cv2.put(COL_ALERT_TIME, datetime_t2);
				long rv2 = db.insert(DB_SCHEDULED_TABLE_NAME, null, cv2);
				
				if(include3){
					ContentValues cv3 = new ContentValues();
					cv3.put(COL_ALM_ID, id);
					cv3.put(COL_TYPE_ID, Constant.COLLECT_CLOTHES);
					cv3.put(COL_ALERT_TIME, datetime_t3);
					long rv3 = db.insert(DB_SCHEDULED_TABLE_NAME, null, cv3);
				}
			}
			successflag = (rv1!=-1 /* && rv2!=-1 && rv3!=-1*/);
				
			cur.close();
		}else{ // disabled the task, delete the corresponding scheduled alarm item in the alarmScheduleTime
			int count2 = db.delete(DB_SCHEDULED_TABLE_NAME, COL_ALM_ID + " = " + id, null);
			successflag = count2>0 && count2 <=3;
		}
		
		db.close();
		
		successflag = successflag && count==1;
		if(Log.LOGV){
			if(successflag)
				Log.v(Log.LOGDB, "AlarmDBMgr.setItemEnabled():operation successfully");
			else
				Log.v(Log.LOGDB, "AlarmDBMgr.setItemEnabled():operation failure!!");
		}
		return successflag ;
	}
	
	private boolean deleteItem(long id) {
		SQLiteDatabase db = mSQLiteHelper.getReadableDatabase();
		int count =  db.delete(DB_ENABLED_TABLE_NAME, COL_ALM_ID + "=" + id, null);
		int count2 = db.delete(DB_SCHEDULED_TABLE_NAME, COL_ALM_ID + "=" + id, null);
		db.close();
		boolean successflag = (count == 1 && /*count2 > 0 &&*/ count2 <= 5); //count2 can be 0, when the alarm is disabled
		if(successflag)
			Log.v(Log.LOGDB, "AlarmDBMgr.deleteItem() operation successfully");
		else
			Log.v(Log.LOGDB, "AlarmDBMgr.deleteItem() operation failure!!");
		return successflag ;
	}

	
	public static AlarmDBMgr getMgrInstance(Context context) {
		return new AlarmDBMgr(context); 
	}

//	/**
//	 * Get the latest scheduled alarm.
//	 * @return the alarming time in milliseconds. -1 if no alarm to be reported.
//	 */
//	public AlermTypeTime getLatestAlarm() {
//		SQLiteDatabase db = mSQLiteHelper.getReadableDatabase();
//		Cursor cur = db.query(DB_SCHEDULED_TABLE_NAME, new String[]{COL_ALM_ID, COL_TYPE_ID, "MIN("+COL_ALERT_TIME+")"}, null, null, null, null, null);
//		int col_alm_id = cur.getColumnIndexOrThrow(COL_ALM_ID);
//		int col_type_id = cur.getColumnIndexOrThrow(COL_TYPE_ID);
//		int col_latest_alarm_time = cur.getColumnIndexOrThrow("MIN("+COL_ALERT_TIME+")");
//		
//		cur.moveToFirst();
//		long alarm_id = cur.getLong(col_alm_id);
//		if(alarm_id == 0){
//			cur.close();
//			db.close();
//			Log.v(Log.LOGDB,"AlarmDBMgr.getLatestAlarm(): No item in Scheduled table!");
//			return null;
//		}
//		
//		AlermTypeTime att = new AlermTypeTime();
//		att.alarm_id = alarm_id;
//		att.alarm_type = cur.getInt(col_type_id);
//		att.alarm_time = cur.getLong(col_latest_alarm_time);
//		
//		cur.close();
//		db.close();
//		Log.v(Log.LOGDB,"AlarmDBMgr.getLatestAlarm(): count = "+ cur.getCount() + ", "+att.toString());
//		return att;
//	}
	
	
	/**
	 * Getting a cursor that contains the alarms in the alarmScheduledTable.
	 * @return
	 */
	public Cursor getLatestAlarm2() {
		SQLiteDatabase db = mSQLiteHelper.getReadableDatabase();
		Cursor cur = db.query(DB_SCHEDULED_TABLE_NAME, new String[]{COL_ALM_ID, COL_TYPE_ID, COL_ALERT_TIME}, 
				COL_ALERT_TIME + " IN (SELECT MIN(" + COL_ALERT_TIME+ ") FROM "+DB_SCHEDULED_TABLE_NAME+")", null, null, null, null);
		return cur;
	}
	
	public  class AlermTypeTime {
		public long alarm_id;
		public int alarm_type;
		public long alarm_time;
		
		public String toString(){
			String typestr = "";
			switch(alarm_type){
			case Constant.WASH_CLOTHES:
				typestr = "WASH";
				break;
			case Constant.DRY_CLOTHES:
				typestr = "DRY";
				break;
			case Constant.COLLECT_CLOTHES:
				typestr = "COLLECT";
				break;
				default:
					typestr = "UNKOWN_TYPE!!";
			}
			Calendar c = Calendar.getInstance();
			c.setTimeInMillis(alarm_time);
			return "AlertTypeTime: id="+alarm_id+", type_id="+alarm_type+", type="+typestr+", time="+c.getTime().toString();
		}
	}
	
//	public boolean deleteAlertedAlarm(long alarm_id, int laundry_type) {
//		SQLiteDatabase db = mSQLiteHelper.getReadableDatabase();
//		int count = db.delete(DB_SCHEDULED_TABLE_NAME, COL_ALM_ID + " = " + alarm_id + " and " + COL_TYPE_ID + " = " + laundry_type + " and " +
//				COL_ALERT_TIME + " = (" + "SELECT MIN("+COL_ALERT_TIME+") FROM "+DB_SCHEDULED_TABLE_NAME+")", null);
//		db.close();
//		boolean successflag = count ==1;
//		Log.v(Log.LOGDB, COL_ALM_ID + " = " + alarm_id + " and " + COL_TYPE_ID + " = " + laundry_type + " and " +
//				COL_ALERT_TIME + " = (" + "SELECT MIN("+COL_ALERT_TIME+") FROM "+DB_SCHEDULED_TABLE_NAME+")");
//		if(Log.LOGV){
//			if(successflag)
//				Log.v(Log.LOGDB, "AlarmDBMgr.deleteAlertedAlarm(): delete alarm( id="+alarm_id+", type="+laundry_type+" succesfully!");
//			else
//				Log.v(Log.LOGDB, "AlarmDBMgr.deleteAlertedAlarm(): delete alarm( id="+alarm_id+", type="+laundry_type+" failure!!");
//		}
//		return successflag;
//	}
//	
	/**
	 * 
	 * @param latest_alarm_time
	 */
	public boolean deleteAlertedAlarm2(long latest_alarm_time) {
		SQLiteDatabase db = mSQLiteHelper.getReadableDatabase();
		int count = db.delete(DB_SCHEDULED_TABLE_NAME, COL_ALERT_TIME + " = " + latest_alarm_time, null);
		db.close();
		boolean successflag = count ==1;
		if(Log.LOGV){
			if(successflag)
				Log.v(Log.LOGDB, "AlarmDBMgr.deleteAlertedAlarm(): success!! delete alarm latest_alarm_time="+latest_alarm_time + ", " + count +" item deleted");
			else
				Log.v(Log.LOGDB, "AlarmDBMgr.deleteAlertedAlarm(): failure!! delete alarm latest_alarm_time="+latest_alarm_time + ", " + count +" item deleted");
		}
		return successflag;
	}

	/**
	 * Schedule the next (wash, dry, collect) event into the alarmScheduleTable
	 * @param alarm_id 
	 * @return 
	 */
	public boolean scheduleNextEpoch(long alarm_id) {
		SQLiteDatabase db = mSQLiteHelper.getReadableDatabase();
		long datetime_t1, datetime_t2, datetime_t3;
		Cursor cur = db.query(DB_ENABLED_TABLE_NAME, new String[]{COL_T1, COL_T2, COL_INCLUDE2, COL_T3, COL_INCLUDE3, COL_PERIOD}, COL_ALM_ID + "=" + alarm_id, null, null, null, null/*COL_ALM_ID+" desc"*/);
		int col_t1 = cur.getColumnIndexOrThrow(COL_T1);
		int col_t2 = cur.getColumnIndexOrThrow(COL_T2);
		int col_include2 = cur.getColumnIndexOrThrow(COL_INCLUDE2);
		int col_t3 = cur.getColumnIndexOrThrow(COL_T3);
		int col_include3 = cur.getColumnIndexOrThrow(COL_INCLUDE3);
		int col_period = cur.getColumnIndexOrThrow(COL_PERIOD);
		Log.v(Log.LOGDB, "AlarmDBMgr.scheduleNextEpoch():id = "+alarm_id);
		dump();
		if(cur.getCount()!=1){
			return false;
//			throw new java.lang.Error("cur.getCount() = " + cur.getCount());
		}
		cur.moveToFirst();

		long milli_t1 = cur.getLong(col_t1);
		long milli_t2 = cur.getLong(col_t2);
		boolean include2 = cur.getInt(col_include2) == 1;
		long milli_t3 = cur.getLong(col_t3);
		boolean include3 = cur.getInt(col_include3) == 1;
		
		int period = cur.getInt(col_period);
		
		if(Log.LOGV){
			Log.v(Log.LOGDB, "AlarmDBMgr.scheduleNextEpoch():");
			TimeUtil.reportTimeInDay("t1", milli_t1);
			TimeUtil.reportTimeInDay("t2", milli_t2);
			Log.v(Log.LOGDB, "t2 is "+(include2?"included":"Not included"));
			TimeUtil.reportTimeInDay("t3", milli_t3);
			Log.v(Log.LOGDB, "t3 is "+(include3?"included":"Not included"));
		}
		
		Calendar c_t1 = Alarms.calculateAlarm2(milli_t1, period);
		Calendar c_t2 = Alarms.calculateAlarm2(milli_t1+milli_t2, period);
		Calendar c_t3 = Alarms.calculateAlarm2(milli_t1+milli_t2+milli_t3, period);
		if(Log.LOGV){
			Log.v(Log.LOGDB, "AlarmDBMgr.scheduleNextEpoch():");
			TimeUtil.reportCalendarTime("ct1", c_t1);
			TimeUtil.reportCalendarTime("ct2", c_t2);
			TimeUtil.reportCalendarTime("ct3", c_t3);
		}
						
		datetime_t1 = c_t1.getTimeInMillis();
		datetime_t2 = c_t2.getTimeInMillis();
		datetime_t3 = c_t3.getTimeInMillis();
		if(Log.LOGV){
			Log.v(Log.LOGDB, "AlarmDBMgr.scheduleNextEpoch():");
			TimeUtil.reportTimeMillis("dt1", datetime_t1);
			TimeUtil.reportTimeMillis("dt2", datetime_t2);
			TimeUtil.reportTimeMillis("dt3", datetime_t3);
		}
		
		ContentValues cv1 = new ContentValues();
		cv1.put(COL_ALM_ID, alarm_id);
		cv1.put(COL_TYPE_ID, Constant.WASH_CLOTHES);
		cv1.put(COL_ALERT_TIME, datetime_t1);
		long rv1 = db.insert(DB_SCHEDULED_TABLE_NAME, null, cv1);
		
		if(include2){
			ContentValues cv2 = new ContentValues();
			cv2.put(COL_ALM_ID, alarm_id);
			cv2.put(COL_TYPE_ID, Constant.DRY_CLOTHES);
			cv2.put(COL_ALERT_TIME, datetime_t2);
			long rv2 = db.insert(DB_SCHEDULED_TABLE_NAME, null, cv2);
		}
		
		if(include3){
			ContentValues cv3 = new ContentValues();
			cv3.put(COL_ALM_ID, alarm_id);
			cv3.put(COL_TYPE_ID, Constant.COLLECT_CLOTHES);
			cv3.put(COL_ALERT_TIME, datetime_t3);
			long rv3 = db.insert(DB_SCHEDULED_TABLE_NAME, null, cv3);
		}
		cur.close();

		boolean successflag = (rv1!=-1 /*&& rv2!=-1 && rv3!=-1*/);
		if(Log.LOGV){
			if(successflag)
				Log.v(Log.LOGDB, "AlarmDBMgr.deleteAlertedAlarm(): delete succesfully!");
			else
				Log.v(Log.LOGDB, "AlarmDBMgr.deleteAlertedAlarm(): delete failure!!");
		}
		return successflag;
	}
	

	/**
	 * Written By WJJ
	 * Schedule the next (wash, dry, collect) event into the alarmScheduleTable
	 * @param alarm_id 
	 * @return 
	 */
	// TODO must be according to the current value
	public boolean scheduleNextEpoch2(long alarm_id) {
		SQLiteDatabase db = mSQLiteHelper.getReadableDatabase();
		Cursor cur = db.query(DB_ENABLED_TABLE_NAME, new String[]{COL_PERIOD}, 
				COL_ALM_ID + "=" + alarm_id, null, null, null, null/*COL_ALM_ID+" desc"*/);
		int col_period = cur.getColumnIndexOrThrow(COL_PERIOD);
		Log.v(Log.LOGDB, "AlarmDBMgr.scheduleNextEpoch2():id = "+alarm_id);
//		dump();
		if(!cur.moveToFirst()){
			cur.close();
			db.close();
			Log.v(Log.LOGDB, "AlarmDBMgr.scheduleNextEpoch2():0 matches id = "+alarm_id + "@" + DB_ENABLED_TABLE_NAME);
			return false;
		}
		int period = cur.getInt(col_period);
		cur.close();
		
		boolean successflag = true;
		
		Cursor item_allAlarms_cursor = db.query(DB_SCHEDULED_TABLE_NAME, new String[]{COL_ALERT_TIME}, 
				COL_ALM_ID + "=" + alarm_id, null, null, null, null);
		if(!item_allAlarms_cursor.moveToFirst()){
			item_allAlarms_cursor.close();
			db.close();
			Log.v(Log.LOGDB, "AlarmDBMgr.scheduleNextEpoch2():0 matches id = "+alarm_id  + "@" + DB_SCHEDULED_TABLE_NAME);
			return false;
		}
		
		int col_alert = item_allAlarms_cursor.getColumnIndexOrThrow(COL_ALERT_TIME); 
		
		do{
			long alert = item_allAlarms_cursor.getLong(col_alert);
			Calendar c = Calendar.getInstance();
			c.setTimeInMillis(alert);
			c.add(Calendar.DATE, period);
			long alert_after = c.getTimeInMillis();
			ContentValues cv = new ContentValues();
			cv.put(COL_ALERT_TIME, alert_after);
			db.update(DB_SCHEDULED_TABLE_NAME, cv, 
					COL_ALM_ID + "=" + alarm_id + " AND " + COL_ALERT_TIME + "=" + alert, null);
		}while(item_allAlarms_cursor.moveToNext());
		
		db.close();
		return successflag;
	}
	
	/**
	 * Cancel currentEpoch, if the user do not want to wash clothes this time.
	 * @return
	 */
	public boolean cancelCurrentEpoch(long alarm_id) {
		Log.v(Log.LOGDB, "AlarmDBMgr.cancelCurrentEpoch():id = "+alarm_id);
		SQLiteDatabase db = mSQLiteHelper.getReadableDatabase();
		int count = db.delete(DB_SCHEDULED_TABLE_NAME, COL_ALM_ID + "="+alarm_id, null);
		Log.v(Log.LOGDB, "AlarmDBMgr.scheduleNextEpoch(): "+count+" be cancelled");
		
		boolean successflag = count<3;
		if(Log.LOGV){
			if(successflag)
				Log.v(Log.LOGDB, "AlarmDBMgr.cancelCurrentEpoch(): delete succesfully!");
			else
				Log.v(Log.LOGDB, "AlarmDBMgr.cancelCurrentEpoch(): delete failure!!");
		}
		return successflag;
	}
	

	public void dump() {
		dumpEnabledTable();
		dumpScheduledTable();
	}
	public void dumpEnabledTable(){
		SQLiteDatabase db = mSQLiteHelper.getReadableDatabase();
		Cursor cur = db.query(DB_ENABLED_TABLE_NAME, new String[]{COL_ALM_ID,COL_PERIOD,COL_ENABLED, COL_T1,COL_T2, COL_T3}, null, null, null, null, null/*COL_ALM_ID+" desc"*/);
		int col_alm_id = cur.getColumnIndexOrThrow(COL_ALM_ID);
		int col_period = cur.getColumnIndexOrThrow(COL_PERIOD );
		int col_enabled = cur.getColumnIndexOrThrow(COL_ENABLED );
		int col_t1 = cur.getColumnIndexOrThrow(COL_T1 );
		int col_t2 = cur.getColumnIndexOrThrow(COL_T2 );
		int col_t3 = cur.getColumnIndexOrThrow(COL_T3 );
		Time t1,t2,t3;
		Log.v(Log.LOGDB, "-----"+DB_ENABLED_TABLE_NAME +"-----");
		while(cur.moveToNext()){
			t1 = new Time(cur.getInt(col_t1));
			t2 = new Time(cur.getInt(col_t2));
			t3 = new Time(cur.getInt(col_t3));
			Log.v(Log.LOGDB, "ALM_ID="+cur.getLong(col_alm_id)+", " +
							"PERIOD="+cur.getInt(col_period)+", " +
							"ENABLED="+cur.getInt(col_enabled)+", " +
							"T1="+t1.toString()+", " +
							"T2="+t2.toString()+", " +
							"T3="+t3.toString()+");");
		}
		Log.v(Log.LOGDB, "-------------------------------------");

		cur.close();
		db.close();
	}
	public void dumpScheduledTable(){
		SQLiteDatabase db = mSQLiteHelper.getReadableDatabase();
		Cursor cur2 = db.query(DB_SCHEDULED_TABLE_NAME, new String[]{COL_ALM_ID,COL_TYPE_ID ,COL_ALERT_TIME}, null, null, null, null, null);
		int col_alm_id2 = cur2.getColumnIndexOrThrow(COL_ALM_ID);
		int col_type_id = cur2.getColumnIndexOrThrow(COL_TYPE_ID );
		int col_alert_time = cur2.getColumnIndexOrThrow(COL_ALERT_TIME );
        Calendar c = Calendar.getInstance();
		Log.v(Log.LOGDB, "-----"+DB_SCHEDULED_TABLE_NAME+" -----------");
		while(cur2.moveToNext()){
			c.setTimeInMillis(cur2.getLong(col_alert_time));
			Log.v(Log.LOGDB, "ALM_ID="+cur2.getLong(col_alm_id2)+", " +
							"TYPE_ID="+cur2.getLong(col_type_id)+", " +
							"ALERT_TIME="+c.getTime().toString()+");");
		}
		Log.v(Log.LOGDB, "--------------------------------------");

		cur2.close();
		
		db.close();
	}

	/***
	 * Written By WJJ
	 * Update time of the alerted alarm to the next epoch 
	 * @param latest_alarm_time
	 * @return
	 */
	public boolean updateAlertedAlarm2(long latest_alarm_time, long item_id) {
		Log.v(Log.LOGDB, "updateAlertedAlarm2()");
		SQLiteDatabase db = mSQLiteHelper.getReadableDatabase();
		Cursor cursor_enabled = db.query(DB_ENABLED_TABLE_NAME, 
				new String[]{COL_PERIOD}, COL_ALM_ID + " = " + item_id,
				null, null, null, null);
		int col_period = cursor_enabled.getColumnIndexOrThrow(COL_PERIOD);
		if(!cursor_enabled.moveToFirst())
		{
			Log.v(Log.LOGDB, "updateAlertedAlarm2(): 0 item matching latest_alarm_item, id" 
		+ "(" + latest_alarm_time  + ", "+ item_id +")");
			return false;
		}		
		int item_period = cursor_enabled.getInt(col_period);
		cursor_enabled.close();
		
		
		ContentValues cv = new ContentValues();
		//what if the period is not 1? but 7?!
		Calendar c = Calendar.getInstance();
        c.setTimeInMillis(latest_alarm_time);
        c.add(Calendar.DATE, item_period);
		Log.v(Log.LOGDB, "updateAlertedAlarm2():" + "item_period = " + item_period);
		long value = c.getTimeInMillis();
		cv.put(COL_ALERT_TIME, value);
		int count = db.update(DB_SCHEDULED_TABLE_NAME, cv, COL_ALERT_TIME + "=" + latest_alarm_time
				+ " AND " + COL_ALM_ID + "=" + item_id , null);
		boolean successflag = count ==1;
		if(Log.LOGV){
			if(successflag)
				Log.v(Log.LOGDB, "AlarmDBMgr.updateAlertedAlarm(): success!! update alarm latest_alarm_time="+latest_alarm_time + ", " + count +" item updated");
			else
				Log.v(Log.LOGDB, "AlarmDBMgr.updateAlertedAlarm(): failure!! update alarm latest_alarm_time="+latest_alarm_time + ", " + count +" item updated");
		}
		db.close();
		return successflag;
		
	}

	/***
	 * Written By WJJ
	 * @param currentTimeMillis
	 * @return the cursor indicating the latest alarm after currentTimeMills
	 */
	public Cursor getLatestAlarm2(long currentTimeMillis) {
		// TODO Auto-generated method stub
		SQLiteDatabase db = mSQLiteHelper.getReadableDatabase();
		Cursor cur = db.query(DB_SCHEDULED_TABLE_NAME, new String[]{COL_ALM_ID, COL_TYPE_ID, COL_ALERT_TIME}, 
				COL_ALERT_TIME + " IN (SELECT MIN(" + COL_ALERT_TIME+ ") FROM "+DB_SCHEDULED_TABLE_NAME+ 
				" WHERE " + COL_ALERT_TIME + ">" + currentTimeMillis + ")", null, null, null, null);
		return cur;
	}

	/***
	 * Written By WJJ
	 * @param alarm_id
	 * @param type_id
	 * @return
	 */
	public long getNextStepScheduleTime(long alarm_id, int type_id) {
		long time = -1;
		int nextstep = type_id+1;
		SQLiteDatabase db = mSQLiteHelper.getReadableDatabase();
		Cursor cur = db.query(DB_SCHEDULED_TABLE_NAME, new String[]{COL_ALM_ID, COL_TYPE_ID, COL_ALERT_TIME}, 
				COL_ALM_ID +"=" + alarm_id + " AND " + COL_TYPE_ID + "=" + nextstep, null, null, null, null);
		if(cur.moveToFirst()){
			int col_time = cur.getColumnIndexOrThrow(COL_ALERT_TIME);
			time = cur.getLong(col_time);
		}
		cur.close();
		db.close();
		return time;
	}

	



}

